package biolean.files;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Obsahuje funkcie pre citanie a zapis sekvencneho suboru po riadkoch.
 * @author Rasto
 */
public class SequenceFile extends BioFile {

	private final int SEQ_TEXT_WRAP = 70;
	private final int SEQ_BUILDER_SIZE = 1024;
	
	private String crossLine;

	
	public SequenceFile()
	{
		super(0,0, "");
	}
	
	public SequenceFile(String fileName) 
	{
		super(0 ,0, fileName );
	}
	
	/**
	 * Precita dalsiu sekvenciu v subore.
	 * @return Vracia najdenu sekvenciu.
	 */
	public Sequence readSeq() throws IOException
	{
		// crossLine is the line where last call of readSeqData() has ended
		if (crossLine != null && isNameLine(crossLine)) 
		{
			String name = getFirstWord(crossLine).substring(1);
			String data = readSeqData();
			if ((name.length() > 0) && (data.length() > 0)) 
			{
				return new Sequence(name, data);
			}
		}
		// read until you find something
		String line;
		while ((line = mReader.readLine()) != null) 
		{
			if (isNameLine(line)) 
			{
				String name = getFirstWord(line).substring(1);
				String data = readSeqData();
				if ((name.length() > 0) && (data.length() > 0)) 
				{
					return new Sequence(name, data);
				}
			}
		}
		return null;
	}
	
	/**
	 * Zapise sekvenciu do suboru.
	 * @param seqName - nazov sekvencie.
	 * @param seqData - data sekvencie.
	 * @return Vrati zoznam riadkov.
	 */
	public void writeSeq(Sequence seq) throws IOException
	{
		if ((seq.getName().length() == 0) || (seq.getData().length() == 0)) 
		{
			return;
		}
		mWriter.write(Sequence.SEQUENCE_MARK+seq.getName());
		mWriter.newLine();
		List<String> lines = breakToLines(seq.getData());
		for (String line: lines) 
		{
			mWriter.write(line);
			mWriter.newLine();
		}
		// mWriter.newLine();	
	}

	/**
	 * Precita data sekvencie od aktualnej pozice az do konca.
	 * @return Vracia data sekvencie.
	 */
	private String readSeqData() throws IOException
	{
		StringBuilder data = new StringBuilder(SEQ_BUILDER_SIZE);
		String line;
		while ((line = mReader.readLine()) != null)
		{
			if (isDataLine(line))
			{
				data.append(line.trim());
			} else 
			{
				crossLine = line;
				break;
			}
		}
		return data.toString();
	}

	/**
	 * @param line - Vstupny riadok.
	 * @return Vracia true ak riadok obsahuje definiciu sekvencie.
	 */
	private boolean isNameLine(String line) 
	{
		return (line.length() > 0) && (line.charAt(0) == Sequence.SEQUENCE_MARK);
	}

	/**
	 * @param line - Vstupny riadok.
	 * @return Vracia true ak riadok obsahuje sekvencne data.
	 */
	private boolean isDataLine(String line) 
	{
		return (line.length() > 0) && (line.charAt(0) != Sequence.SEQUENCE_MARK);
	}

	/**
	 * @param sentence - Vstupny text.
	 * @return Vracia prve slovo v texte.
	 */
	private String getFirstWord(String sentence) 
	{
		return sentence.split("\\s+", 2)[0];
	}

	/**
	 * Rozdeli retazec na riadky.
	 * @param string - Textovy retazec.
	 * @return Vrati zoznam riadkov.
	 */
	private List<String> breakToLines(String string) 
	{
		List<String> lines = new ArrayList<String>();
		StringBuilder line = new StringBuilder(SEQ_TEXT_WRAP);
		for (int i = 0; i < string.length(); i++) {
			line.append(string.charAt(i));
			if (line.length() == SEQ_TEXT_WRAP) {
				lines.add(line.toString());
				line = new StringBuilder(SEQ_TEXT_WRAP);
			}
			if ((string.length() == i + 1) && (line.length() != SEQ_TEXT_WRAP)) {
				lines.add(line.toString());
			}
		}
		return lines;
	}
}
